ネクストキーロック next-key lock
ギャップロック gap lock+レコードロック record lock
W、Y、Zのレコードがあったとする
キー範囲(ロックの単位)は
$ ( A,W\rbrack、$ ( W,Y\rbrack、$ ( Y,Z\rbrack、$ ( Z,\infty)
ちなみに閉区間を前に持ってくることも考えられる
previous-key lock
書き込みすることを考える
Xを挿入すると
$ ( A,W\rbrack、$ ( W,X\rbrack、$ ( X,Y\rbrack、$ ( Y,Z\rbrack、$ ( Z,\infty)
Yを削除すると
$ ( A,W\rbrack、$ ( W,Z\rbrack、$ ( Z,\infty)
なにが問題かというとキー範囲は書き込みによって消える
? 現れる場合はたぶんそんなに問題ない
Yが消えると$ ( Y,Z\rbrackのロックをとっていたトランザクションは$ ( W,Z\rbrackのロックを取り直すことになる
排他ロックを許可してしまうとロッキングプロトコル locking protocolに従わなくなる
ロックをとれるかどうかはロックの要求時に返すもの、一度取得したロックをトランザクションの要求なしに変更することはできない
だからギャップロックに関するロックはロック両立性行列 compatibility matrixで偽だとしてもロックを取得できる
ギャップロック同士は競合しない
? 挿入阻止する必要あるのかな。挿入されたら分割されたキー範囲を新たに取得すればいいだけ?ロッキングプロトコル違反?
挿入インテントロック insert intent lock
すでにギャップロックを取得している範囲にレコードを挿入されるとキー範囲が変化し困る(ということにする。上の?)
レコードのinsertを防ぎたいがその範囲のギャップロックを取得するだけでは不十分
なぜならギャップロック同士は競合しない
insert前にロック取得を試みてinsertを防止する
今までメンタルモデルとして共有ロックや排他ロックがinsertを防止してると思ってたけど、ロックをとらないinsert(が存在するとして)は他のトランザクションがロックをとってたとしても防げない
のでは?
2086でギャップロックとった(空打ちselect for update)あと2087でinsertした例
INSERT_INTENTIONは挿入した後すぐ消えるっぽい
2PCに従ってないのではという気がする
GAPも同時にとる意味あるのか
MySQL的にintet lockはgap lockのパターンの一種という位置づけだからか
code:mysql
$ mysql -uroot d -e "select * from performance_schema.data_locks\G"
*************************** 1. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 139652271000984:1064:139652203886864
ENGINE_TRANSACTION_ID: 2087
THREAD_ID: 53
EVENT_ID: 37
OBJECT_SCHEMA: d
OBJECT_NAME: t
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139652203886864
LOCK_TYPE: TABLE
LOCK_MODE: IX
LOCK_STATUS: GRANTED
LOCK_DATA: NULL
*************************** 2. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 139652271000984:2:4:3:139652203883952
ENGINE_TRANSACTION_ID: 2087
THREAD_ID: 53
EVENT_ID: 37
OBJECT_SCHEMA: d
OBJECT_NAME: t
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139652203883952
LOCK_TYPE: RECORD
LOCK_MODE: X,GAP,INSERT_INTENTION
LOCK_STATUS: WAITING
LOCK_DATA: 5
*************************** 3. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 139652271001840:1064:139652203893008
ENGINE_TRANSACTION_ID: 2086
THREAD_ID: 66
EVENT_ID: 22
OBJECT_SCHEMA: d
OBJECT_NAME: t
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 139652203893008
LOCK_TYPE: TABLE
LOCK_MODE: IX
LOCK_STATUS: GRANTED
LOCK_DATA: NULL
*************************** 4. row ***************************
ENGINE: INNODB
ENGINE_LOCK_ID: 139652271001840:2:4:3:139652203890096
ENGINE_TRANSACTION_ID: 2086
THREAD_ID: 66
EVENT_ID: 22
OBJECT_SCHEMA: d
OBJECT_NAME: t
PARTITION_NAME: NULL
SUBPARTITION_NAME: NULL
INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 139652203890096
LOCK_TYPE: RECORD
LOCK_MODE: X,GAP
LOCK_STATUS: GRANTED
LOCK_DATA: 5
ネクストキーロックってそもそもなんで存在してるんだっけ?という話に戻るとファントム phantomを防ぐため
デッドロック deadlockが発生することは別に問題にしてない
なぜネクストキーロックなのか
なぜ述語ロック Predicate Locksではないのか
コストの問題
ネクストキーロックにすることでレコードロックと(ある程度)透過的に扱える
MySQLの実装
IN句でのwhereならばギャップロックを取得しないか